package modifyx

import (
	"gitee.com/zhongguo168a/gocodes/datax/convertx"
	"strconv"
)

func (s *Object) RefClassName() string {
	return s.source.className
}

// 新建一个对象
func NewObject(src *Source) (obj *Object) {
	obj = newObject()
	obj.source = src
	//
	obj.sourceData = src.origin
	obj.path = src.className
	obj.initData()

	return
}

func newObject() (obj *Object) {
	obj = &Object{}
	obj.ints = map[string]int{}
	obj.uints = map[string]uint{}
	obj.floats = map[string]float64{}
	obj.strings = map[string]string{}
	obj.bools = map[string]bool{}
	obj.temps = map[string]interface{}{}
	obj.runtime = map[string]interface{}{}
	obj.disablePoolField = map[string]bool{}
	return
}

// 修正对象
// 如果需要在运行时，替换源的数据，可通过设置runtime实现
type Object struct {
	source *Source
	// 字段的路径
	path string
	// 在父对象中的字段名字
	field string
	// 父数据
	parent map[string]interface{}
	// 缓存的map/array/struct等对象, 避免重复创建对象
	temps map[string]interface{}
	//
	creators map[string]func(obj IObject) IObject
	creator  func(obj IObject) IObject
	// 当前修正对象指向的源数据
	sourceData      map[string]interface{}
	sourceDataArray []interface{}
	// 运行时设置的数据
	runtime map[string]interface{}
	// 最终的数据, 采用不同类型的原因是，初始值
	ints    map[string]int
	uints   map[string]uint
	floats  map[string]float64
	strings map[string]string
	bools   map[string]bool
	// 需要使用修正池修正的字段
	// 用于性能优化，避免进入修正池流程。
	disablePoolField map[string]bool
	//
	disabelPool bool
}

func (s *Object) RefClassCreator(field string, creator func(object IObject) IObject) {
	if s.creators == nil {
		s.creators = map[string]func(obj IObject) IObject{}
	}
	s.creators[field] = creator
}

func (s *Object) initData() {
	for key, val := range s.sourceData {
		switch v := val.(type) {
		//case int:
		//	s.ints[key] = v
		//case uint:
		//	s.uints[key] = v
		//case float64:
		//	s.floats[key] = v
		case bool:
			s.bools[key] = v
		case string:
			s.strings[key] = v
		}
	}
}

func (s *Object) getOriginBool(field string) bool {
	// 运行时
	if rval, has := s.runtime[field]; has {
		return rval.(bool)
	}
	return convertx.AnyToBool(s.sourceData[field])
}

func (s *Object) getOriginFloat(field string) float64 {
	// 运行时
	if rval, has := s.runtime[field]; has {
		return rval.(float64)
	}
	return convertx.AnyToFloat64(s.sourceData[field])
}
func (s *Object) getOriginInt(field string) int {
	// 运行时
	if rval, has := s.runtime[field]; has {
		return rval.(int)
	}
	return convertx.AnyToInt(s.sourceData[field])
}

func (s *Object) Dispose() {
	s.sourceData = nil
	s.runtime = nil
	s.ints = nil
	s.floats = nil
	s.strings = nil
	s.bools = nil
	s.parent = nil
	s.temps = nil
	s.source = nil
}

// 修正后的整型
func (s *Object) RefInt(field string) int {
	origin := s.getOriginInt(field)
	s.ints[field] = origin
	// 池修正
	if !s.disabelPool {
		if !s.disablePoolField[field] {
			pools := s.source.pools
			if pools != nil {
				lastkey := s.path + "/" + field
				if pools.IsPropChanged(lastkey) {
					// 更新属性
					s.ints[field] = pools.GetNewPropInt(lastkey, origin)
				}
			}
		}
	}

	return s.ints[field]

}

func (s *Object) resetBool(field string) {
	// 运行时
	if rval, has := s.runtime[field]; has {
		s.bools[field] = rval.(bool)
	} else {
		// 使用源数据进行初始化B
		s.bools[field] = convertx.AnyToBool(s.sourceData[field])
	}
	return
}

// 修正后的整型
func (s *Object) RefBool(field string) bool {
	origin := s.getOriginBool(field)
	s.bools[field] = origin
	// 池修正
	if !s.disabelPool {
		if !s.disablePoolField[field] {
			pools := s.source.pools
			if pools != nil {
				lastkey := s.path + "/" + field
				if pools.IsPropChanged(lastkey) {
					// 更新属性
					s.bools[field] = pools.GetNewPropBool(lastkey, origin)
				}
			}
		}
	}

	return s.bools[field]
}

// 修正后的浮点型
func (s *Object) RefFloat64(field string) float64 {
	origin := s.getOriginFloat(field)
	s.floats[field] = origin
	// 池修正
	if !s.disabelPool {
		if !s.disablePoolField[field] {
			pools := s.source.pools
			if pools != nil {
				lastkey := s.path + "/" + field
				if pools.IsPropChanged(lastkey) {
					// 更新属性
					s.floats[field] = pools.GetNewPropFloat(lastkey, origin)
				}
			}
		}
	}

	return s.floats[field]

}

// RefSourceData 获取原始数据
// 可通过 mapx.Int(origin, fieldName)获取指定内容的值
func (s *Object) RefSourceData() (origin map[string]interface{}) {
	return s.sourceData
}

// RefSource 获取原始数据指定的字段
func (s *Object) RefSource(field string) interface{} {
	return s.sourceData[field]
}

func (s *Object) RefUint(field string) (val uint) {
	return uint(s.RefInt(field))
}

func (s *Object) resetString(field string) {
	// 运行时
	if rval, has := s.runtime[field]; has {
		s.strings[field] = rval.(string)
	} else {
		// 使用源数据进行初始化B
		s.strings[field] = convertx.AnyToString(s.sourceData[field])
	}
	return
}

func (s *Object) RefString(field string) (val string) {
	// 池修正
	//if !s.disabelPool {
	//	if !s.disablePoolField[field] {
	//		root := s.source.root
	//		versions := s.source.versions
	//		if root != nil {
	//			lastkey := s.path + "/" + field
	//			pool := root.GetPool()
	//			if pool.IsPropChanged(lastkey, versions[lastkey]) {
	//				// 更新属性
	//				s.resetString(field)
	//				s.strings[field], versions[lastkey] = pool.GetNewPropString(root, lastkey, s.strings[field])
	//			}
	//		}
	//
	//	}
	//}

	return s.strings[field]
}

func (s *Object) RefArray(field string) (r IArray) {
	iobj, hastemp := s.temps[field]
	if hastemp == false {
		obj := newArray()
		obj.source = s.source
		obj.parent = s.sourceData
		obj.field = field
		obj.path = s.path + "/" + field
		obj.creator = s.creators[field]
		//
		m, has := s.sourceData[field]
		if has == true && m != nil {
			switch mval := m.(type) {
			case []interface{}:
				obj.sourceData = mval
			case map[string]interface{}:
				max := func() (x int) {
					for key := range mval {
						index, _ := strconv.Atoi(key)
						if index > x {
							x = index
						}
					}
					return
				}()
				obj.sourceData = make([]interface{}, max, max)
				for key, val := range mval {
					index, _ := strconv.Atoi(key)
					obj.sourceData[index] = val
				}
			}

			obj.initData()
		}
		iobj = obj
		s.temps[field] = iobj
	}

	r = iobj.(IArray)
	return
}

func (s *Object) RefMap(field string) (r IObject) {
	iobj, hastemp := s.temps[field]
	if hastemp == false {
		obj := newObject()
		obj.source = s.source
		obj.parent = s.sourceData
		obj.field = field
		obj.path = s.path + "/" + field
		obj.temps = map[string]interface{}{}
		//
		m, has := s.sourceData[field]
		if has == true && m != nil {
			obj.sourceData = m.(map[string]interface{})
			obj.initData()
		}

		creator, hascreator := s.creators[field]
		if hascreator {
			obj.creator = creator
		}
		iobj = obj
		s.temps[field] = iobj
	}

	r = iobj.(IObject)
	return
}

func (s *Object) RefObject(field string) (r IObject) {
	iobj, hastemp := s.temps[field]
	if hastemp == false {
		obj := newObject()
		obj.source = s.source
		obj.parent = s.sourceData
		obj.field = field
		obj.path = s.path + "/" + field
		obj.temps = map[string]interface{}{}
		//
		m, has := s.sourceData[field]
		if has == true && m != nil {
			obj.sourceData = m.(map[string]interface{})
			obj.initData()
		}

		if s.creator != nil { // 只有map对象会有此属性
			iobj = s.creator(obj)
		} else {
			//
			creator, hascreator := s.creators[field]
			if !hascreator {
				iobj = obj
			} else {
				iobj = creator(obj)
			}

		}

		s.temps[field] = iobj
	}

	r = iobj.(IObject)
	return
}

// SetRuntimeFloat 运行时修改的数据, 用于直接替换掉origin数据, 再进行池修正
// 用于已知目标的情况下使用, 可提高运行效率, 例如初始化时, 为目标单位赋予初值
// 注: 需要注意设置的类型
func (s *Object) SetRuntimeFloat(field string, val float64) {
	s.runtime[field] = val
	s.floats[field] = val
}
func (s *Object) SetRuntimeInt(field string, val int) {
	s.runtime[field] = val
	s.ints[field] = val
}
func (s *Object) SetRuntimeBool(field string, val bool) {
	s.runtime[field] = val
	s.bools[field] = val
}
func (s *Object) SetRuntimeString(field string, val string) {
	s.runtime[field] = val
	s.strings[field] = val
}

func (s *Object) RefIsNil() bool {
	return s.sourceData == nil
}

func (s *Object) RefLength() int {
	return len(s.sourceData)
}

func (s *Object) RefKeys() (r []string) {
	if s.RefIsNil() {
		return
	}

	for key := range s.sourceData {
		r = append(r, key)
	}
	return
}

// 只用于无修正场合
func (s *Object) MapKeyOf(conf func(item interface{}) bool) string {
	if s.RefIsNil() {
		return ""
	}

	for key := range s.sourceData {
		if conf(s.sourceData[key]) {
			return key
		}
	}

	return ""
}

func (s *Object) GetMapFloat() (r map[string]float64) {
	iobj, hastemp := s.temps["mapfloat"]
	if hastemp == false {
		r = map[string]float64{}
		iobj = r
		s.temps["mapfloat"] = r
	}
	r = iobj.(map[string]float64)
	for key := range s.sourceData {
		r[key] = s.RefFloat64(key)
	}
	return
}

func (s *Object) GetMapFloatModify() (r map[string]float64) {
	iobj, hastemp := s.temps["mapfloatmod"]
	if hastemp == false {
		r = map[string]float64{}
		iobj = r
		s.temps["mapfloatmod"] = r
	}
	r = iobj.(map[string]float64)
	for key := range s.sourceData {
		r[key] = s.RefFloat64(key)
	}
	return
}

// 只用于无修正场合
func (s *Object) ToMapString() (r map[string]string) {
	iobj, hastemp := s.temps["mapstring"]
	if hastemp == false {
		r = map[string]string{}
		for key := range s.sourceData {
			r[key] = s.sourceData[key].(string)
		}
		iobj = r
		s.temps["mapstring"] = r
	}
	r = iobj.(map[string]string)
	return
}

// 只用于无修正场合
func (s *Object) ToArrayString() (r []string) {
	iobj, hastemp := s.temps["arraystring"]
	if hastemp == false {
		r = make([]string, s.RefLength())
		for key, val := range s.sourceData {
			idx := convertx.AnyToInt64(key)
			r[idx] = val.(string)
		}
		iobj = r
		s.temps["arraystring"] = r
	}
	r = iobj.([]string)
	return
}

// 只用于无修正场合
func (s *Object) GetArrayFloatModify() (r []float64) {
	iobj, hastemp := s.temps["arrayfloat64mod"]
	if hastemp == false {
		r = make([]float64, s.RefLength())
		iobj = r
		s.temps["arrayfloat64mod"] = r
	}
	for key := range s.sourceData {
		idx := convertx.AnyToInt64(key)
		r[idx] = s.RefFloat64(key)
	}
	r = iobj.([]float64)
	return
}
